/**
 * ChatModel - 聊天模型类
 * 基于 Augment Code 的聊天管理机制
 */

import { EventEmitter } from 'events';
import { 
  ChatMode,
  AIModel,
  ToolExecutor,
  MemoryManager,
  StreamEvent,
  PromptConfig,
  SendRequest,
  NodeType,
  StructuredNode
} from './types';
import { ConversationModel } from './conversation-model';
import { PromptBuilder } from './prompt-builder';

export interface ChatModelConfig {
  aiModel: AIModel;
  toolExecutors?: ToolExecutor[];
  memoryManager?: MemoryManager;
  defaultMode?: ChatMode;
  promptConfig?: Partial<PromptConfig>;
}

export class ChatModel extends EventEmitter {
  private conversations = new Map<string, ConversationModel>();
  private currentConversationId: string | null = null;
  private promptBuilder: PromptBuilder;
  private config: ChatModelConfig;

  constructor(config: ChatModelConfig) {
    super();
    this.config = config;
    this.promptBuilder = new PromptBuilder(config.promptConfig);
  }

  /**
   * 创建新对话
   */
  createConversation(
    conversationId?: string,
    mode: ChatMode = this.config.defaultMode || ChatMode.CHAT
  ): ConversationModel {
    const id = conversationId || this.generateConversationId();
    
    if (this.conversations.has(id)) {
      throw new Error(`Conversation with id ${id} already exists`);
    }

    const conversation = new ConversationModel(id, mode, this.promptBuilder);
    
    // 设置事件监听
    this.setupConversationListeners(conversation);
    
    this.conversations.set(id, conversation);
    this.currentConversationId = id;
    
    this.emit('conversationCreated', { id, mode });
    
    return conversation;
  }

  /**
   * 获取当前对话
   */
  getCurrentConversation(): ConversationModel | null {
    if (!this.currentConversationId) return null;
    return this.conversations.get(this.currentConversationId) || null;
  }

  /**
   * 切换到指定对话
   */
  switchToConversation(conversationId: string): ConversationModel {
    const conversation = this.conversations.get(conversationId);
    if (!conversation) {
      throw new Error(`Conversation with id ${conversationId} not found`);
    }
    
    this.currentConversationId = conversationId;
    this.emit('conversationSwitched', conversationId);
    
    return conversation;
  }

  /**
   * 发送消息到当前对话
   */
  async sendMessage(request: SendRequest): Promise<void> {
    const conversation = this.getCurrentConversation();
    if (!conversation) {
      throw new Error('No active conversation');
    }

    const requestId = await conversation.sendMessage(request);
    
    // 开始流式处理
    await this.processStreamingResponse(conversation, request, requestId);
  }

  /**
   * 处理流式响应
   */
  private async processStreamingResponse(
    conversation: ConversationModel,
    request: SendRequest,
    requestId: string
  ): Promise<void> {
    try {
      const context = conversation.getContext();
      const prompt = this.promptBuilder.buildPrompt(request.requestMessage, context);
      
      // 使用 AI 模型生成流式响应
      const responseStream = this.config.aiModel.generateResponse(prompt, context);
      
      for await (const event of responseStream) {
        await this.handleStreamEvent(conversation, event, requestId);
      }
      
      conversation.completeTurn();
      
    } catch (error) {
      conversation.completeTurn('failed' as any);
      this.emit('error', { error, requestId });
      throw error;
    }
  }

  /**
   * 处理流式事件
   */
  private async handleStreamEvent(
    conversation: ConversationModel,
    event: StreamEvent,
    requestId: string
  ): Promise<void> {
    this.emit('streamEvent', event);

    switch (event.type) {
      case 'start':
        this.emit('responseStarted', { requestId });
        break;

      case 'chunk':
        // 处理文本块
        if (event.data.text) {
          const node: StructuredNode = {
            type: NodeType.RawResponse,
            ts: event.timestamp,
            requestId,
            text: event.data.text
          } as any;
          conversation.addNode(node);
        }
        break;

      case 'node':
        // 处理结构化节点
        if (event.nodeType && event.data) {
          const node = this.createStructuredNode(event.nodeType, event.data, requestId);
          conversation.addNode(node);
          
          // 处理特殊节点类型
          await this.handleSpecialNodes(conversation, node);
        }
        break;

      case 'tool':
        // 处理工具调用
        await this.handleToolExecution(conversation, event.data, requestId);
        break;

      case 'end':
        this.emit('responseCompleted', { requestId });
        break;

      case 'error':
        this.emit('responseError', { error: event.data, requestId });
        break;
    }
  }

  /**
   * 创建结构化节点
   */
  private createStructuredNode(
    nodeType: NodeType,
    data: any,
    requestId: string
  ): StructuredNode {
    const baseNode = {
      type: nodeType,
      ts: Date.now(),
      requestId
    };

    switch (nodeType) {
      case NodeType.RawResponse:
        return { ...baseNode, text: data.text || '' } as any;
      
      case NodeType.SuggestedQuestions:
        return { ...baseNode, questions: data.questions || [] } as any;
      
      case NodeType.ToolUse:
        return { 
          ...baseNode, 
          tool: data.tool,
          input: data.input,
          result: data.result,
          error: data.error
        } as any;
      
      case NodeType.ToolUseStart:
        return {
          ...baseNode,
          tool: data.tool,
          input: data.input
        } as any;
      
      case NodeType.AgentMemory:
        return {
          ...baseNode,
          memoryId: data.memoryId,
          content: data.content
        } as any;
      
      case NodeType.Thinking:
        return { ...baseNode, text: data.text } as any;
      
      case NodeType.MainTextFinished:
        return baseNode as any;
      
      default:
        return baseNode as any;
    }
  }

  /**
   * 处理特殊节点
   */
  private async handleSpecialNodes(
    conversation: ConversationModel,
    node: StructuredNode
  ): Promise<void> {
    switch (node.type) {
      case NodeType.AgentMemory:
        // 处理记忆节点
        if (this.config.memoryManager) {
          const memoryNode = node as any;
          try {
            const memory = await this.config.memoryManager.saveMemory({
              content: memoryNode.content,
              source: 'agent',
              state: 'pending'
            });
            conversation.addMemory(memory);
          } catch (error) {
            console.error('Failed to save memory:', error);
          }
        }
        break;
      
      case NodeType.SuggestedQuestions:
        // 处理建议问题
        this.emit('suggestedQuestions', (node as any).questions);
        break;
    }
  }

  /**
   * 处理工具执行
   */
  private async handleToolExecution(
    conversation: ConversationModel,
    toolData: any,
    requestId: string
  ): Promise<void> {
    const { tool, input } = toolData;
    
    // 添加工具开始节点
    const startNode: StructuredNode = {
      type: NodeType.ToolUseStart,
      ts: Date.now(),
      requestId,
      tool,
      input
    } as any;
    conversation.addNode(startNode);

    // 查找合适的工具执行器
    const executor = this.config.toolExecutors?.find(e => e.canExecute(tool));
    
    if (!executor) {
      const errorNode: StructuredNode = {
        type: NodeType.ToolUse,
        ts: Date.now(),
        requestId,
        tool,
        input,
        error: `No executor found for tool: ${tool}`
      } as any;
      conversation.addNode(errorNode);
      return;
    }

    try {
      const result = await executor.execute(tool, input, conversation.getContext());
      
      const resultNode: StructuredNode = {
        type: NodeType.ToolUse,
        ts: Date.now(),
        requestId,
        tool,
        input,
        result: result.result,
        error: result.error
      } as any;
      conversation.addNode(resultNode);
      
    } catch (error) {
      const errorNode: StructuredNode = {
        type: NodeType.ToolUse,
        ts: Date.now(),
        requestId,
        tool,
        input,
        error: error instanceof Error ? error.message : String(error)
      } as any;
      conversation.addNode(errorNode);
    }
  }

  /**
   * 删除对话
   */
  deleteConversation(conversationId: string): boolean {
    const conversation = this.conversations.get(conversationId);
    if (!conversation) return false;
    
    conversation.removeAllListeners();
    this.conversations.delete(conversationId);
    
    if (this.currentConversationId === conversationId) {
      this.currentConversationId = null;
    }
    
    this.emit('conversationDeleted', conversationId);
    return true;
  }

  /**
   * 获取所有对话ID
   */
  getConversationIds(): string[] {
    return Array.from(this.conversations.keys());
  }

  /**
   * 设置对话事件监听器
   */
  private setupConversationListeners(conversation: ConversationModel): void {
    conversation.on('turnStarted', (turn) => {
      this.emit('turnStarted', { conversationId: conversation.getContext().id, turn });
    });
    
    conversation.on('turnCompleted', (turn) => {
      this.emit('turnCompleted', { conversationId: conversation.getContext().id, turn });
    });
    
    conversation.on('nodeAdded', ({ turn, node }) => {
      this.emit('nodeAdded', { conversationId: conversation.getContext().id, turn, node });
    });
  }

  /**
   * 生成对话ID
   */
  private generateConversationId(): string {
    return `conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 更新配置
   */
  updateConfig(config: Partial<ChatModelConfig>): void {
    this.config = { ...this.config, ...config };
    if (config.promptConfig) {
      this.promptBuilder.updateConfig(config.promptConfig);
    }
  }

  /**
   * 获取配置
   */
  getConfig(): ChatModelConfig {
    return { ...this.config };
  }
}
